#pragma once

#include <iostream>
#include <time.h>
#include <stdarg.h>

#define Info 1
#define Warning 2
#define Error 3
#define Fatal 4
#define Debug 5
#define SIZE 1024

#define SCREEN 1   // 将日志显示在屏幕上
#define ONE_FILE 2 // 将日志存放到一个文件中

#define FILE_LOG "./log.txt"

class Log
{
public:
    Log(int type = SCREEN)
        : _type(type)
    {
    }

    void operator()(int level, const char *format, ...)
    {
        // 左半部分是日志的等级和时间
        char left_log[SIZE];
        time_t ctime = time(nullptr);
        struct tm *ct = localtime(&ctime);
        snprintf(left_log, sizeof(left_log), "[%s][%d/%d/%d %d:%d:%d]", Tostring(level).c_str(),
                 ct->tm_year + 1900, ct->tm_mon + 1, ct->tm_mday, ct->tm_hour, ct->tm_min, ct->tm_sec);

        // std::cout << leftlog << std::endl;

        // 右半部分是日志的内容
        va_list s;
        va_start(s, format);
        char right_log[SIZE];

        vsnprintf(right_log, sizeof(right_log), format, s);

        char total_log[SIZE * 2];
        snprintf(total_log, sizeof(total_log), "%s %s\n", left_log, right_log);

        // 显示日志
        PrintLog(total_log, _type);
        va_end(s);
    }

private:
    void save_screen(const std::string &log)
    {
        // 将日志输出到显示器上
        std::cout << log << std::endl;
    }

    void save_one_file(const std::string &log)
    {
        // 打开文件
        int fd = open(FILE_LOG, O_CREAT | O_APPEND | O_WRONLY, 0666);
        write(fd, log.c_str(), log.size());
        close(fd);
    }

    void PrintLog(const std::string &log, int type)
    {
        switch (type)
        {
        // 向屏幕显示日志
        case SCREEN:
            save_screen(log);
            break;

        // 向文件保存日志
        case ONE_FILE:
            save_one_file(log);
            break;
        default:
            std::cout << "save filed!" << std::endl;
            break;
        }
    }
    std::string Tostring(int level)
    {
        switch (level)
        {
        case Info:
            return "Info";
            break;
        case Warning:
            return "Warning";
            break;
        case Error:
            return "Error";
            break;
        case Fatal:
            return "Fatal";
            break;
        case Debug:
            return "Debug";
            break;
        default:
            return "None";
            break;
        }
    }
    int _type; // 用于表示将日志显示到哪里
};